home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1998 March
/
Macworld (1998-03) (Disk 1).dmg
/
Shareware World
/
Info
/
For Developers
/
GhostScript 5.10
/
MacGS-510
/
files
/
pdf_main.ps
< prev
next >
Wrap
Text File
|
1997-07-19
|
15KB
|
508 lines
% Copyright (C) 1994, 1996, 1997 Aladdin Enterprises. All rights reserved.
%
% This file is part of Aladdin Ghostscript.
%
% Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
% or distributor accepts any responsibility for the consequences of using it,
% or for whether it serves any particular purpose or works at all, unless he
% or she says so in writing. Refer to the Aladdin Ghostscript Free Public
% License (the "License") for full details.
%
% Every copy of Aladdin Ghostscript must include a copy of the License,
% normally in a plain ASCII text file named PUBLIC. The License grants you
% the right to copy, modify and redistribute Aladdin Ghostscript, but only
% under certain conditions described in the License. Among other things, the
% License requires that the copyright notice and this notice be preserved on
% all copies.
% pdf_main.ps
% PDF file- and page-level operations.
% We handle the following PDF 1.2 constructs:
% page number rather than page object in Dest array
% We explicitly ignore the following PDF 1.2 constructs:
% "Marked content" operators
/.setlanguagelevel where { pop 2 .setlanguagelevel } if
.currentglobal true .setglobal
/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
pdfdict begin
% For simplicity, we use a single interpretation dictionary for all
% PDF graphics execution, even though this is too liberal.
/pdfopdict mark
objopdict { } forall
drawopdict { } forall
/endstream { exit } bind
(%%EOF) cvn { exit } bind % for filters
% PDF 1.1 operators
/BX { /BXlevel BXlevel 1 add store } bind
/EX { /BXlevel BXlevel 1 sub store } bind
% PDF 1.2 operators
/BMC { pop } bind
/BDC { pop pop } bind
/EMC { }
/MP { pop } bind
/DP { pop pop } bind
.dicttomark readonly def
% ======================== Main program ======================== %
end % pdfdict
userdict begin
/defaultfontname /Times-Roman def
% Make sure the registered encodings are loaded, so we don't run the risk
% that some of the indices for their names will overflow the packed
% representation. (Yes, this is a hack.)
SymbolEncoding pop
DingbatsEncoding pop
% Redefine 'run' so it recognizes PDF files.
systemdict begin
/.runps /run load def
/runpdfstring 50 string def % length is arbitrary
/run
{ dup type /filetype ne { (r) file } if
dup read
{ dup (%) 0 get eq
{ pop dup //runpdfstring
% Some invalid files might have extra-long first lines....
{ { readline } .internalstopped not { pop pop exit } if
pop =string
}
loop
//runpdfstring (PDF-) anchorsearch
{ pop pop runpdf }
{ pop cvx .runexec }
ifelse
}
{ 2 copy unread pop .runps
}
ifelse
}
{ closefile
}
ifelse
} bind odef
/runpdf % <file> runpdf -
{ userdict begin
/PSFile where { pop PSFile (w) file /PSout exch def } if
/Page# null def
/Page null def
/DSCPageCount 0 def
/PDFSave null def
GS_PDF_ProcSet begin
pdfdict begin
pdfopen begin
Trailer /Root oget /Pages oget /CropBox knownoget
{ mark /CropBox 3 -1 roll /PAGES pdfmark
}
if
/FirstPage where { pop FirstPage } { 1 } ifelse
1
/LastPage where { pop LastPage } { pdfpagecount } ifelse
QUIET not
{ (Processing pages ) print 2 index =only ( through ) print dup =only
(.\n) print flush
}
if
{ dup /Page# exch store
QUIET not { (Page ) print dup == flush } if
pdfgetpage pdfshowpage
} for
currentdict pdfclose
end % temporary dict
end % pdfdict
end % userdict
} bind def
end % systemdict
% Redefine the procedure that the C code uses for running piped input.
% It is OK to use { (%stdin) run } here, because a startjob cannot occur.
/.runstdin {
{ (%stdin) run } execute0
} bind def
end % userdict
pdfdict begin
% ======================== File parsing ======================== %
% Read the cross-reference and trailer sections.
/traileropdict mark
(<<) cvn { mark } bind
(>>) cvn /.dicttomark load
([) cvn { mark } bind % ditto
(]) cvn dup load
/true true
/false false
/null null
/R { /resolveR cvx 3 packedarray cvx } bind % see Objects below
/startxref /exit load
.dicttomark readonly def
% Because of EOL conversion, lines with fixed contents might be followed
% by one or more blanks.
/lineeq % <filestr> <conststr> lineeq <bool>
{ anchorsearch
{ pop { ( ) anchorsearch not { () eq exit } if pop } loop }
{ pop false }
ifelse
} bind def
/linene { lineeq not } bind def
% Read (mostly scan) the cross-reference table.
/readxref % <pos> readxref <trailerdict>
{ PDFoffset add PDFfile exch setfileposition
% In some PDF files, this position actually points to
% white space before the xref line. Skip over this here.
{ PDFfile fileposition PDFfile read pop 32 gt { exit } if pop
} loop
PDFfile exch setfileposition
PDFfile pdfstring readline pop
(xref) linene { /readxref cvx /syntaxerror signalerror } if
% Store the xref table entry position for each object.
% We only need to read the run headers, not every entry.
{ PDFfile token pop % first object # or trailer
dup /trailer eq { pop exit } if
PDFfile pdfstring readline pop
token pop % entry count
exch pop exch
% This section might be adding new objects:
% ensure that Objects and Generations are big enough.
% Stack: count obj#
2 copy add
dup Objects llength gt
{ dup Objects exch lgrowto /Objects exch def }
if
dup Generations llength gt
{ dup Generations exch lgrowto /Generations exch def }
if
pop
PDFfile fileposition 3 -1 roll
{ Objects 2 index lget null eq % later update might have set it
{ Objects 2 index 2 index cvx lput }
if exch 1 add exch 20 add
}
repeat PDFfile exch setfileposition pop
} loop
PDFfile traileropdict .pdfrun
} bind def
% Open a PDF file and read the trailer and cross-reference.
/pdfopen % <file> pdfopen <dict>
{ pdfdict readonly pop % can't do it any earlier than this
/PSout where { pop /pdf2psdict where { pop pdf2psdict begin } if } if
10 dict begin
/PSLevel1 where { pop } { /PSLevel1 false def } ifelse
cvlit /PDFfile exch def
/PDFsource PDFfile def
PDFfile dup 0 setfileposition pdfstring readstring
not {/pdfopen cvx /syntaxerror signalerror} if
(%PDF-) search not {/pdfopen cvx /syntaxerror signalerror} if
length /PDFoffset exch def pop pop
PDFfile dup dup 0 setfileposition bytesavailable
% Scan backwards over trailing control-character garbage
% (nulls, ^Zs, EOLs).
{ 1 sub 2 copy setfileposition 1 index read pop
32 ge {exit} if
} loop 1 sub setfileposition
prevline (%%EOF) linene { /pdfopen cvx /syntaxerror signalerror } if
PDFfile exch setfileposition
prevline cvi % xref start position
exch PDFfile exch setfileposition
prevline (startxref) linene { /pdfopen cvx /syntaxerror signalerror } if
pop
% Stack: xrefpos
/Objects larray def
/Generations lstring def
% Read the last cross-reference table.
readxref /Trailer exch def
Trailer /Encrypt known
{ pdf_process_Encrypt % signal error
}
if
% Read any previous cross-reference tables.
Trailer { /Prev .knownget not { exit } if readxref } loop
% Create and initialize some caches.
/PageCount pdfpagecount def
/PageNumbers PageCount dict def
/PageIndex PageCount array def
% Write the DSC header if appropriate.
[ (%!PS-Adobe-1.0) #dsc
[ (%%Pages: (atend)) #dsc
[ (%%EndComments) #dsc
[ (%%BeginProlog) #dsc
[ (% This copyright applies to everything between here and the %%EndProlog:) #dsc
[ (% ) copyright #dsc
(gs_pdf.ps) #dscfile
PSLevel1 { (gs_l2img.ps) #dscfile } if
[ (%%EndProlog) #dsc
% Copy bookmarks (outline) to the output.
#?
{ Trailer /Root oget /Outlines knownoget
{ /First knownoget
{ { dup writeoutline /Next knownoget not { exit } if } loop }
if
}
if
}
if
currentdict end
} bind def
% Write the outline structure for a file. Uses linkdest (below).
/writeoutline % <outlinedict> writeoutline -
{ mark
0 2 index /First knownoget
{ { exch 1 add exch /Next knownoget not { exit } if } loop }
if
% stack: dict mark count
dup 0 eq
{ pop 1 index
}
{ 2 index /Count knownoget { 0 lt { neg } if } if
/Count exch 3 index
}
ifelse linkdest /Title oget /Title exch /OUT pdfmark
/First knownoget
{ { dup writeoutline /Next knownoget not { exit } if } loop }
if
} bind def
% Close a PDF file.
/pdfclose % <dict> pdfclose -
{ begin
/PSout where
{ pop
[ (%%Trailer) #dsc
[ (%%Pages: ) DSCPageCount #dsc
PSout closefile
}
if
PDFfile closefile
end
pdf2psdict where { pop currentdict pdf2psdict eq { end } if } if
} bind def
% ======================== Page accessing ======================== %
% Get a (possibly inherited) attribute of a page.
/pget % <pagedict> <key> pget <value> -true-
% <pagedict> <key> pget -false-
{ 2 copy knownoget
{ exch pop exch pop true
}
{ exch /Parent knownoget
{ exch pget }
{ pop false }
ifelse
}
ifelse
} bind def
% Get the value of a resource on a given page.
/rget % <resname> <pagedict> <restype> rget <value> -true-
% <resname> <pagedict> <restype> rget -false-
{ exch /Resources pget
{ exch knownoget
{ exch knownoget }
{ pop false }
ifelse
}
{ pop pop false
}
ifelse
} bind def
% Get the total number of pages in the document.
/pdfpagecount % - pdfpagecount <int>
{ Trailer /Root oget /Pages oget /Count oget
} bind def
% Find the N'th page of the document by iterating through the Pages tree.
% The first page is numbered 1.
/pdffindpage % <int> pdffindpage <pagedict>
{ dup Trailer /Root oget /Pages oget
{ % We should be able to tell when we reach a leaf
% by finding a Type unequal to /Pages. Unfortunately,
% some files distributed by Adobe lack the Type key
% in some of the Pages nodes! Instead, we check for Kids.
dup /Kids knownoget not { exit } if
exch pop null
0 1 3 index length 1 sub
{ 2 index exch oget
dup /Kids known { dup /Count oget } { 1 } ifelse
% Stack: index kids null node count
dup 5 index ge { pop exch pop exit } if
5 -1 roll exch sub 4 1 roll pop
}
for exch pop
dup null eq { pop pop 1 null exit } if
}
loop
% Stack: index countleft node
1 index 1 ne { pop pop /pdffindpage cvx /rangecheck signalerror } if
exch pop
PageIndex 2 index 1 sub 2 index put
PageNumbers 1 index 3 index put
exch pop
} bind def
% Find the N'th page of the document.
% The first page is numbered 1.
/pdfgetpage % <int> pdfgetpage <pagedict>
{ PageIndex 1 index 1 sub get dup null ne
{ exch pop }
{ pop pdffindpage }
ifelse
} bind def
% Find the page number of a page object (inverse of pdfgetpage).
/pdfpagenumber % <pagedict> pdfpagenumber <int>
{ % We use the simplest and stupidest of all possible algorithms....
PageNumbers 1 index .knownget
{ exch pop
}
{ 1 1 PageCount 1 add % will give a rangecheck if not found
{ dup pdfgetpage oforce 2 index eq { exit } if pop
}
for exch pop
}
ifelse
} bind def
% Display a given page.
/boxrect % [<llx> <lly> <urx> <ury>] boxrect <x> <y> <w> <h>
{ aload pop exch 3 index sub exch 2 index sub
} bind def
/linkdest % <link|outline> linkdest
% ([/Page <n>] /View <view> | ) <link|outline>
{ dup /Dest knownoget
{ % Check for a name, to be looked up in Dests.
dup type /nametype eq
{ Trailer /Root oget /Dests oget exch knownoget
{ dup type /dicttype eq { /D get } if }
{ null }
ifelse
}
if
dup null eq
{ pop }
{ dup 0 oget
dup null eq
{ pop }
{ dup type /integertype ne { pdfpagenumber } if
/Page exch 4 -2 roll
}
ifelse
dup length 1 sub 1 exch getinterval /View exch 3 -1 roll
}
ifelse
}
if
} bind def
/annottypes 5 dict dup begin
/Text
{ mark exch
{ /Rect /Open /Contents }
{ 2 copy knownoget { 3 -1 roll } { pop } ifelse }
forall pop /ANN pdfmark
} bind def
/Link
{ mark exch
{ /Rect /Border }
{ 2 copy knownoget { 3 -1 roll } { pop } ifelse }
forall linkdest pop /LNK pdfmark
} bind def
end def
/pdfshowpage % <pagedict> pdfshowpage -
{ dup /Page exch store
pdfshowpage_init
pdfshowpage_setpage
save /PDFSave exch store
(before exec) VMDEBUG
pdfshowpage_finish
(after exec) VMDEBUG
PDFSave restore
} bind def
/pdfpagecontents % <pagedict> pdfpagecontents <contents>
{ } bind def
/pdfshowpage_init % <pagedict> pdfshowpage_init <pagedict>
{ gsave
[ (%%Page: ) Page# ( )
DSCPageCount 1 add /DSCPageCount 1 index store #dsc
[ (GS_PDF_ProcSet begin) #dsc
} bind def
/pdfshowpage_setpage % <pagedict> pdfshowpage_setpage <pagedict>
{
3 dict % for setpagedevice
% Stack: pagedict setpagedict
% We want to look at Rotate for displays, but not for printers.
% The following is a hack, but we don't know a better way to do this.
currentpagedevice /OutputFile known
/PSout where dup { exch pop } if or not
{ dup /Orientation 3 index /Rotate pget not { 0 } if 90 idiv
% Rotate specifies *clockwise* rotation!
neg 3 and put
}
if
% Stack: pagedict setpagedict
1 index /MediaBox pget
{ % Set the page size.
boxrect [ 2 index 5 index sub 2 index 5 index sub ]
% Stack: pagedict setpagedict llx lly urx ury pagesize
5 index exch /PageSize exch put
% Stack: pagedict contents setpagedict llx lly urx ury
pop pop
neg exch neg exch
[ 3 1 roll ]
% Stack: pagedict setpagedict pageoffset
1 index exch /PageOffset exch put
}
if
% Stack: pagedict setpagedict
/setpagedevice 1 #
} bind def
/pdfshowpage_finish % <pagedict> pdfshowpage_finish -
{
% Copy crop box.
dup /CropBox pget
{ boxrect rectclip
dup /CropBox knownoget { mark /CropBox 3 -1 roll /PAGE pdfmark } if
}
if
% Copy annotations and links.
dup /Annots knownoget
{ 0 1 2 index length 1 sub
{ 1 index exch oget
dup /Subtype oget annottypes exch .knownget { exec } { pop } ifelse
}
for pop
}
if
% Display the actual page contents.
2 dict begin
/BXlevel 0 def
matrix currentmatrix /beginpage 0 # setmatrix
/Contents knownoget not { 0 array } if
dup type /arraytype ne { 1 array astore } if
{ oforce false resolvestream pdfopdict .pdfrun } forall
/endpage 0 #
end % scratch dict
grestore
[ (end) #dsc
} bind def
end % pdfdict
.setglobal